//
//  DataManager.m
//  iFlickr
//
//  Created by 张 霄鹤 on 09-5-31.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import "DataManager.h"

#import "MD5.h"

#import "XMLRPCRequest.h"

#import "XMLRPCResponse.h"

#import "XMLRPCConnection.h"

#import "DebugDefine.h"

#import "PhotosetInfo.h"

#import "DocumentBuilder.h"

#import "Element.h"

#import "TextNode.h"


#import "PhotoInfo.h"

static DataManager *dataManager = NULL;

@implementation DataManager

/**
 * 静态调用入口
 */
+(id) sharedDataManager{
	if(!dataManager){
		dataManager = [[DataManager alloc]  initWithApikeyAndSecret:@"32fdd35bca5b784340c0bdf523b9d3cc" secret:@"fe8a457a3077648b"];
	}
	return dataManager;
}

+(id) alloc{
	dataManager = [super alloc];
	return dataManager;
}

/**
 * 通过指定 api_key, secret 来创建 flickr账户
 */
-(id)initWithApikeyAndSecret:(NSString *)api_key secret:(NSString *)key;{
	if(self = [super init]){
		apiKey = api_key;
		secretKey = key;
		frob = @"";
		// 固定的，多成分数据提交时候的分割符
		desc = @"CAFEBABE09329837ADEF";
		// 可重用的结果解析器
		//fparser = [[FlickrParser alloc] init];     // TODO 此处是否需要改进
		userInfo = [[UserInfo alloc] init];
		uploadItems = [[NSMutableArray alloc] init];
	}
	return self;
}

#pragma mark -
#pragma mark 辅助功能


/**
 * 创建默认参数，添加 api_key
 */
-(NSMutableDictionary *)initParams{
	NSMutableDictionary *ret = [NSMutableDictionary dictionaryWithObject:apiKey forKey:@"api_key"];
	return [ret autorelease];
}

/**
 * 检查 doc 中是否包含 <rsp stat=""> 标记，并且察看 stat 属性
 */
-(int)isRspFail:(Document *)doc{
	int bret = PARSE_RSP_NO_RSP;
	Element *el = [doc rootNode];
	if(el){
		NSString *ename = [el getNodeName];
		if([ename isEqualToString:@"rsp"]){
			NSString *stat = [el getAttribute:@"stat"];
			if(stat){
				if([stat isEqualToString:@"fail"]){
					bret = PARSE_RSP_FAILD;
				}else{
					bret = PARSE_RSP_OK;
				}
			}
		}
	}
	return bret;
}

/**
 * 获取当前注册用户的ID
 */
-(NSString *) currentUserID{
	// TODO 获取用户 nsid
	if(userInfo){
		return userInfo.nsid;
	}
	return nil;
}
/**
 * 获取当前登录的用户名
 * @return NSString name
 */
-(NSString *) currentUserName{
	if(userInfo){
		return userInfo.userName;
	}
	return nil;
}

/**
 * 执行远程请求
 */
-(id)invokeRemoteMethod:(NSString *)url withMethod:(NSString *)method params:(NSDictionary *)param{
	id ret = nil;
	XMLRPCRequest *req = [[[XMLRPCRequest alloc] initWithHost:[NSURL URLWithString:url]] autorelease];
	[req setMethod:method withObject:param];
	ret = [XMLRPCConnection sendSynchronousXMLRPCRequest:req];
	
	return ret;
}


#pragma mark -
#pragma mark flickr功能

/**
 * 获取 frob 并且生成授权地址，用于用户授权
 */
-(NSURL *) getFrobAndAuthURL{
	NSString *method = @"nil";
	// 获取 frob
	NSString *f = [self getFrobFromServer];
	if(![f isEqualToString:@"Error"]){
		
		// 获取成功
		NSMutableDictionary *dict = [self initParams];
		// 权限指定为 write
		[dict setObject:@"write" forKey:@"perms"];
		[dict setObject:f forKey:@"frob"];
		// 方法签名
		NSString *apisig = [self genApiSign:method params:dict];
		
		// 生成授权请求地址
		NSURL *ret = [[NSURL alloc]
					  initWithString:[NSString
					  stringWithFormat:@"http://m.flickr.com/services/auth/?api_key=%@&perms=write&frob=%@&api_sig=%@",
					  apiKey,f,apisig]];
		return [ret autorelease];
	}
	return nil;
	
}

/**
 * 计算方法的签名
 * 签名方法 toHexStr(MD5(secretKeyparampairs))
 */
-(NSString *)genApiSign:(NSString *)method params:(NSDictionary *)paramDict{
	NSMutableString *ret = [NSMutableString stringWithString:secretKey];
	// [paramDict setValue:apiKey forKey:@"api_key"];	
	NSArray * keys = [[paramDict keyEnumerator] allObjects];
	// 此方法会创建一个新的NSArray，但是不会拷贝原有数组的元素，只是包含引用
	NSArray *akeys = [keys sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)];
	for(id key in akeys){
		[ret appendFormat:@"%@%@",key,[paramDict objectForKey:key]];
	}
	// 注意，keys akeys 这两个不是在这个方法中创建的，就不需要release了
	
	const char *us = [ret UTF8String];
	
	
	int len = strlen(us);
	MD5 m = MD5WithBytes(us,len);
	NSString * sret = MD5ToString(&m);
	return sret;
}

/**
 * 从服务器端获取frob
 * @return NSString frob
 */
-(NSString *)getFrobFromServer{
	NSMutableDictionary *data = [self initParams];
	NSString *method = @"flickr.auth.getFrob";
	NSString *sig = [self genApiSign:method params:data];
	[data setValue:sig forKey:@"api_sig"];
	
	//XMLRPCRequest *req = [[XMLRPCRequest alloc] initWithHost:[NSURL URLWithString:@"http://api.flickr.com/services/xmlrpc/"]];
//	[req setMethod:method withObject:data];
//	XMLRPCResponse * resp = [XMLRPCConnection sendSynchronousXMLRPCRequest:req];
//	// TODO req 没有释放
//	[req release];
	XMLRPCResponse *resp = [self invokeRemoteMethod:@"http://api.flickr.com/services/xmlrpc/" withMethod:method params:data];
	
	NSString *ret;
	
	id obj;
	if([resp isKindOfClass:[XMLRPCResponse class]]){	
		obj = [resp object];
		
		NSString *xml = obj;
		
		DocumentBuilder *dombuilder = [[DocumentBuilder alloc] init];
		Document *dom = [dombuilder parseWithString:xml];
		[dombuilder release];

		Element *txt = [dom query:@"frob/#TEXT"];
		if(txt){
			TextNode *tn = (TextNode *)txt;
			frob = tn.text;
			ret = tn.text;
		}
	}else if([resp isKindOfClass:[NSError class]]){
		// NSError *err = resp;
		ret = [NSString stringWithString:@"Error"];
	}
	return ret;
}

-(NSString *)getUserToken{
	NSMutableDictionary *data = [self initParams];
	[data setValue:frob forKey:@"frob"];
	NSString *method = @"flickr.auth.getToken";
	
	NSString *sig = [self genApiSign:method params:data];
	[data setValue:sig forKey:@"api_sig"];
	
	//XMLRPCRequest *req = [[XMLRPCRequest alloc] initWithHost:[NSURL URLWithString:@"http://api.flickr.com/services/xmlrpc/"]];
//	[req setMethod:method withObject:data];
//	XMLRPCResponse * resp = [XMLRPCConnection sendSynchronousXMLRPCRequest:req];
//	// TODO req 没有释放
//	[req release];
	
	XMLRPCResponse *resp = [self invokeRemoteMethod:@"http://api.flickr.com/services/xmlrpc/" withMethod:method params:data];
	
	NSString *ret = nil;
	if([resp isKindOfClass:[XMLRPCResponse class]]){
		id obj = [resp object];
		NSString *xml = obj;
		
		DocumentBuilder *dombuilder = [[DocumentBuilder alloc] init];
		Document *dom = [dombuilder parseWithString:xml];
		[dombuilder release];
		
		// 解析成功，进行操作
		if(dom){
			TextNode *e_token = (TextNode *)[dom query:@"auth/token/#TEXT"];
			TextNode *e_perms = (TextNode *)[dom query:@"auth/perms/#TEXT"];
			Element *e_user = [dom query:@"auth/user"];
			
			userInfo.auth_token = e_token.text;
			userInfo.perms = e_perms.text;
			userInfo.nsid = [e_user getAttribute:@"nsid"];
			userInfo.userName = [e_user getAttribute:@"username"];
			userInfo.fullName = [e_user getAttribute:@"fullname"];
			[self saveAuthInfo:[userInfo saveInfos]];
		}
		ret = userInfo.auth_token;
	}else if([resp isKindOfClass:[NSError class]]){
		// NSError *err = resp;
		ret = [NSString stringWithString:@"Error"];
	}
	return ret;
}

-(BOOL)loadAuthInfo{
	NSString *resourcePath =  [self applicationDocumentsDirectory];
	// 此处字符串 采用 快捷方式创建，不需要释放
	NSString *plistPath = [resourcePath stringByAppendingPathComponent:@"/userAuth.plist"];
	BOOL bret = NO;
	id iobj = [NSKeyedUnarchiver unarchiveObjectWithFile:plistPath];
	if(iobj){
		NSDictionary *info = (NSDictionary *)iobj;
		// TODO 给属性赋值
		[userInfo loadInfos:info];
		if([userInfo.nsid length] > 0){
			bret = YES;
		}
	}
	return bret;
}

/**
 * 保存用户数据
 */
-(BOOL)saveAuthInfo:(NSDictionary *)info{
	NSString *resourcePath =  [self applicationDocumentsDirectory];
	NSString *plistPath = [resourcePath stringByAppendingPathComponent:@"/userAuth.plist"];
	BOOL bOk = [NSKeyedArchiver archiveRootObject:info toFile:plistPath];
	return bOk;
}

/**
 * 注销用户
 */
-(void)logout{
	userInfo.nsid = @"";
	userInfo.userName = @"";
	userInfo.auth_token = @"";
	userInfo.perms = @"";
	userInfo.fullName = @"";
	[self saveAuthInfo:[userInfo saveInfos]];
	// [info release];
}

/**
 * 判断是否授权了，采用token判断
 */
-(BOOL)isAuthorized{
	return ([userInfo.auth_token length] > 2);
}

#pragma mark -
#pragma mark Upload Items

/**
 * 保存对象到文件
 */
-(BOOL)saveObjectToFile:(id)items withName:(NSString *)path{
	NSString *resourcePath =  [self applicationDocumentsDirectory];
	NSString *plistPath = [resourcePath stringByAppendingPathComponent:path];
	BOOL bOk = [NSKeyedArchiver archiveRootObject:items toFile:plistPath];
	return bOk;
}

/**
 * 加载对象
 */
-(id)loadObjectFromFile:(NSString *)path{
	NSString *resourcePath =  [self applicationDocumentsDirectory];
	// 此处字符串 采用 快捷方式创建，不需要释放
	NSString *plistPath = [resourcePath stringByAppendingPathComponent:path];
	id iobj = [NSKeyedUnarchiver unarchiveObjectWithFile:plistPath];
	return iobj;
}

/**
 * 保存没有上传的图像信息
 */
-(void)saveUnfinishItems{
	int size = [uploadItems count];
	NSMutableArray *arr = [NSMutableArray array];
	UploadItem *uitem;
	for (int i = 0; i<size; i++) {
		uitem = [uploadItems objectAtIndex:i];
		if(uitem.uploadState != US_UPLOADED){
			[arr addObject:uitem];
		}
	}
	[self saveObjectToFile:arr withName:@"/UploadItems.dat"];
}

/**
 * 装载没有上传的图像信息
 */
-(void)loadUnfinishItems{
	id iobj = [self loadObjectFromFile:@"/UploadItems.dat"];
	if(iobj){
		if([iobj isKindOfClass:[NSArray class]]){
			NSArray *arr = (NSArray *)iobj;
			[uploadItems setArray:arr];
		}
	}
}

#pragma mark -
#pragma mark AppDocumentPath
/**
 Returns the path to the application's documents directory.
 */
- (NSString *)applicationDocumentsDirectory {
	// TODO 检查是否包含了 /
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *basePath = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;
    return basePath;
}


#pragma mark UploadImage


/**
 * 添加图像
 */
-(void)notifyUploadItem:(UploadItem *)item{
	[uploadItems addObject:item];
}

/**
 * 获取上传图像内容
 */
-(NSArray *)getUploadItems{
	return uploadItems;
}

/**
 * 删除指定索引的图像信息
 */
-(BOOL)removUploadItemAt:(NSInteger)index{
	BOOL bret = NO;
	int size = [uploadItems count];
	if(index >= 0 && index < size){
		[uploadItems removeObjectAtIndex:index];
	}
	return bret;
}

/**
 * 获取指定位置的UploadItem
 */
-(UploadItem *)getUploadItemAt:(NSInteger)index{
	UploadItem *ret = nil;
	int size = [uploadItems count];
	if(index >= 0 && index < size){
		ret = [uploadItems objectAtIndex:index];
	}
	return ret;
}


/**
 * 提交图片数据到Flickr的服务器
 * @param data NSData 图像的二进制数据
 * @param params 图像标题等信息
 * @return id 
 */
-(id)uploadImageToServer:(NSData *)data withParams:(NSDictionary *)params{
	id iret = nil;
	BOOL bret = NO;
	if(data != nil){
		int len = [data length];
		if(len > 0){
			if(params != nil){
				len = [params count];
				if(len > 0){
					NSMutableDictionary *myParams = [[NSMutableDictionary alloc] initWithDictionary:params];
					id photo = [myParams objectForKey:@"photo"];
					if(photo != nil){
						[myParams removeObjectForKey:@"photo"];
					}
					NSString * title = [params objectForKey:@"title"];
					if(title == nil){
						title = @"Untitled";
						[myParams setValue:title forKey:@"title"];
					}
					[myParams setValue:apiKey forKey:@"api_key"];
					
					[myParams setValue:userInfo.auth_token forKey:@"auth_token"];
					
					NSString *as = [myParams objectForKey:@"api_sig"];
					if(as == nil){
						as = [self genApiSign:@"upload" params:myParams];
						[myParams setValue:as forKey:@"api_sig"];
					}
					[myParams setValue:data forKey:@"photo"];
					NSMutableURLRequest *uploadRequest = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"http://api.flickr.com/services/upload/"]];
					[uploadRequest setHTTPMethod:@"POST"];
					[uploadRequest addValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", desc] forHTTPHeaderField:@"Content-Type"];
					NSData *nData = [self convertMultipart:myParams withDesc:[NSString stringWithFormat:@"--%@",desc]];
					[uploadRequest setHTTPBody:nData];
					
					
					// TODO 继续完成，检查释放情况
					// TODO 使用NSURLConnection实现 POST方式传输
					// NSURLConnection *request = [[NSURLConnection alloc] initWithRequest:uploadRequest delegate:self];
					NSURLResponse *resp = NULL;
					NSError *err = NULL;
					NSData *ret = [NSURLConnection sendSynchronousRequest:uploadRequest returningResponse:&resp error:&err];
					
					// TODO 检查这个释放是否正常
					[uploadRequest release];
					[myParams release];
					
					if(resp){
						[resp release];
					}
					
					if(!ret){
						iret = [err autorelease];
						bret = NO;
					}else{
						// TODO 发送成功

						NSString *xml = [[NSString alloc] initWithData:ret encoding:NSUTF8StringEncoding];
						
						DocumentBuilder *dombuilder = [[DocumentBuilder alloc] init];
						Document *dom = [dombuilder parseWithString:xml];
						[dombuilder release];
						
						// 解析成功，进行操作
						if(dom){
							TextNode *pid = (TextNode *)[dom query:@"photoid/#TEXT"];
							if(pid){
								iret = pid.text;
								bret = YES;
							}
						}
						[xml release];
					}
				}
			}
		}
	}
	return iret;
}

/**
 * 创建 Multipart/form-data
 */
-(NSData *)convertMultipart:(NSDictionary *)params withDesc:(NSString *)de{
	if(params == nil){
		return nil;
	}
	// TODO 实现 multipart/form-data的组合
	NSMutableData *data = [[NSMutableData alloc] init];	

	char newline[2];
	newline[0] = '\n';
	newline[1] = '\n';
	NSString *cheader  = nil;
	NSData *deData = [de dataUsingEncoding:NSUTF8StringEncoding];
	for(id key in params){
		id value = [params objectForKey:key];
		if(![key isEqualToString:@"api_sig"]){
		
		[data appendData:deData]; // 添加 desc
		
		[data appendBytes:newline length:1];  // 换行
		
		cheader = [NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"",key]; // 设置头信息
		
		[data appendData:[cheader dataUsingEncoding:NSUTF8StringEncoding]];
		
		
			if([value isKindOfClass:[NSString class]]){
				[data appendBytes:newline length:2]; // 换两行
				// TODO 检查下面的是否正确
				cheader = [NSString stringWithFormat:@"%@",value];
				[data appendData:[cheader dataUsingEncoding:NSUTF8StringEncoding]];
				
			}else if([value isKindOfClass:[NSData class]]){
				// TODO 添加 filename
				cheader = [NSString stringWithFormat:@"; filename=\"aa.png\"\nContent-Type: application/octet-stream\n\n"];   // 使用 \n\n 实现两行
				[data appendData:[cheader dataUsingEncoding:NSUTF8StringEncoding]];
				
				[data appendData:value];
			}
			[data appendBytes:newline length:1]; // 最后换一行
		}
	}
	
	[data appendData:deData];   // 添加分割
	[data appendBytes:newline length:1];
	
	id sig = [params objectForKey:@"api_sig"];
	cheader = @"Content-Disposition: form-data; name=\"api_sig\"\n\n";		// 设置 api_sig 包含两行
	[data appendData:[cheader dataUsingEncoding:NSUTF8StringEncoding]];

	
	NSString *sd = (NSString *)sig;
	[data appendData:[sd dataUsingEncoding:NSUTF8StringEncoding]];
	[data appendBytes:newline length:1];
	
	[data appendData:deData];
	
	[data appendData:[@"--" dataUsingEncoding:NSUTF8StringEncoding]];
	[data appendBytes:newline length:1];
	return [data autorelease];
}

/**
 * 通过用户id,图片id创建地址
 */
-(NSString *) getPhotoURL:(NSString *)nsid withID:(NSString *)photoid{
	return [NSString stringWithFormat:@"http://www.flickr.com/photos/%@/%@",nsid,photoid];
}

/**
 * 通过网络连接，装载图像
 */
-(UIImage *)loadPhotoWithURL:(NSURL *)url{
	UIImage *ret = nil;
	// TODO 连接地址，进行图像下载
	NSData *imgData = [NSData dataWithContentsOfURL:url];
	if(imgData){
		ret = [UIImage imageWithData:imgData];
	}
	return ret;
}


/*
 
 <photosets cancreate="1">
 <photoset id="5" primary="2483" secret="abcdef"
 server="8" photos="4" farm="1">
 <title>Test</title>
 <description>foo</description>
 </photoset>
 <photoset id="4" primary="1234" secret="832659"
 server="3" photos="12" farm="1">
 <title>My Set</title>
 <description>bar</description>
 </photoset>
 </photosets> 
 
 */


/**
 * 根据用户ID获取Photoset
 * @return 包含了 PhotosetInfo 的数组
 */
-(NSArray *) getPhotosetsByID:(NSString *)nsid{
	
	NSMutableDictionary *data = [self initParams];
	[data setValue:nsid forKey:@"user_id"];
	NSString *method = @"flickr.photosets.getList";
	
	NSString *sig = [self genApiSign:method params:data];
	[data setValue:sig forKey:@"api_sig"];

	
	XMLRPCResponse *resp = [self invokeRemoteMethod:@"http://api.flickr.com/services/xmlrpc/" withMethod:method params:data];
	
	// TODO 处理获取结果中的数据
	
	NSMutableArray *array = [NSMutableArray array];
	
	
	if([resp isKindOfClass:[XMLRPCResponse class]]){
		id ret = [resp object];
		NSString *xml = (NSString *)ret;
		
		// TODO 测试DOM
		
		DocumentBuilder *dombuilder = [[DocumentBuilder alloc] init];
		Document *dom = [dombuilder parseWithString:xml];
		[dombuilder release];
		
		// 查询		
				
		// TODO 使用 DOM 进行处理
		NSArray *ps0 = [dom getElementsByName:@"photoset"];
		if(ps0){
			array = [[[NSMutableArray alloc] init] autorelease];
			int psnum = [ps0 count];
			Element *el = nil;
			TextNode *fd = nil;
			for(int i = 0;i<psnum;i++){
				fd = nil;
				el = [ps0 objectAtIndex:i];
				PhotosetInfo *psinfo = [[[PhotosetInfo alloc] init] autorelease];
				[psinfo setProperties:([el getAttributes])];
				
				fd = (TextNode *)[dom query:[NSString stringWithFormat:@"photosets/photoset[%d]/title/#TEXT",i]];
				psinfo.title = fd.text;
				
				fd = (TextNode *)[dom query:[NSString stringWithFormat:@"photosets/photoset[%d]/description/#TEXT",i]];
				psinfo.description = fd.text;
				
				[array addObject:psinfo];
			}
		}
	}
	else{
		return nil;
	}
	return array;
}

-(BOOL)addPhotoToSet:(NSString *)photoID toSet:(NSString *)setID{
	BOOL bret = NO;
	
	// 发送请求部分
	NSMutableDictionary *data = [self initParams];
	[data setValue:photoID forKey:@"photo_id"];
	[data setValue:setID forKey:@"photoset_id"];
	// 必须加上token认证
	[data setValue:userInfo.auth_token forKey:@"auth_token"];
	
	// 对于 addPhoto 没有返回内容，如果成功，返回空内容
	NSString *method = @"flickr.photosets.addPhoto";
	
	NSString *sig = [self genApiSign:method params:data];
	[data setValue:sig forKey:@"api_sig"];
	
	//XMLRPCRequest *req = [[XMLRPCRequest alloc] initWithHost:[NSURL URLWithString:@"http://api.flickr.com/services/xmlrpc/"]];
//	[req setMethod:method withObject:data];
//	// 此方法如果出错，那么 resp 返回的可能是 NSError
//	XMLRPCResponse * resp = [XMLRPCConnection sendSynchronousXMLRPCRequest:req];
//	// TODO req 释放
//	[req release];
	
	XMLRPCResponse *resp = [self invokeRemoteMethod:@"http://api.flickr.com/services/xmlrpc/" withMethod:method params:data];
	
	if([resp isKindOfClass:[XMLRPCResponse class]]){
		bret = ![resp isFault];
	}
	/*
	else{
		// TODO 出错，不需要处理，直接返回 bret就可以了
	}
	*/
	
	return bret;
}

-(PhotosetInfo *) createPhotoset:(NSDictionary *)params{
	id ret = nil;
	// TODO 说明，对于这种授权检查，还是放在外部去做，这种方法内部就做好请求就可以了
	NSString *title = [params objectForKey:@"title"];
	NSString *errMsg;
	BOOL bOK = NO;
	if(title){
		NSString *primary = [params objectForKey:@"primary_photo_id"];
		if(primary){
			[params setValue:userInfo.auth_token forKey:@"auth_token"];
			NSString *sig = [self genApiSign:@"flickr.photosets.create" params:params];
			[params setValue:sig forKey:@"api_sig"];
			
			//XMLRPCRequest *req = [[XMLRPCRequest alloc] initWithHost:[NSURL URLWithString:@"http://api.flickr.com/services/xmlrpc/"]];
//			[req setMethod:@"flickr.photosets.create" withObject:params];
//			XMLRPCResponse * resp = [XMLRPCConnection sendSynchronousXMLRPCRequest:req];
//			// TODO req 释放
//			[req release];
			
			XMLRPCResponse *resp = [self invokeRemoteMethod:@"http://api.flickr.com/services/xmlrpc/" withMethod:@"flickr.photosets.create" params:params];
			
			
			if([resp isKindOfClass:[XMLRPCResponse class]]){
				id result = [resp object];
				NSString *xml = (NSString *)result;
				
				DocumentBuilder *dombuilder = [[DocumentBuilder alloc] init];
				Document *dom = [dombuilder parseWithString:xml];
				[dombuilder release];
				
				Element *psi = [dom query:@"photoset"];
				if(psi){
					bOK = YES;
					PhotosetInfo *pi = [[[PhotosetInfo alloc] init] autorelease];
					pi.setID = [psi getAttribute:@"id"];
					pi.url = [psi getAttribute:@"url"];
					ret = pi;
				}else{
					// TODO 出错了
					errMsg = @"parse photoset xml error";
				}
				
				//BOOL b1 = [fparser parseString:xml];
//				if(b1){
//					// TODO 请求成功
//					result = [fparser getResult];
//					if(result && [result isKindOfClass:[PhotosetInfo class]]){
//						PhotosetInfo *psi = (PhotosetInfo *)result;
//						ret = psi.setID;
//						bOK = YES;
//					}
//				}
			}else{
				// TODO 出错了
				errMsg = @"XMLRPC Request Error";
			}
			
		}else{
			// TODO 没有设定 primary
			errMsg = @"Must set primary photo";
		}
	}else{
		errMsg = @"Must set photoset title";
	}
	if(!bOK){
		NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:errMsg,NSLocalizedFailureReasonErrorKey,nil];
		ret = [NSError errorWithDomain:@"Flickr" code:-1 userInfo:info];
	}
	return ret;
}

/**
 * 获取没有在Photoset中的图片
 * 调用 flickr.photos.getNotInSet
 * 此方法需要使用 读取 权限
 * 参数 只有 api_key是必须的
 */
-(NSArray *) getNotInSets{
	NSMutableArray *ret = nil;
	NSMutableDictionary *params = [self initParams];
	[params setObject:userInfo.auth_token forKey:@"auth_token"];
	// TODO 获取附加信息，获取小正方形图像的地址，用于显示在图像列表中
	[params setObject:@"url_sq" forKey:@"extras"];
	
	NSString *sig = [self genApiSign:@"flickr.photos.getNotInSet" params:params];
	[params setObject:sig forKey:@"api_sig"];
	
	id obj = [self invokeRemoteMethod:FLICKR_XMLRPC withMethod:@"flickr.photos.getNotInSet" params:params];
	
	if([obj isKindOfClass:[XMLRPCResponse class]]){
		ret = [NSMutableArray array];
		XMLRPCResponse *resp = (XMLRPCResponse *)obj;
		obj = [resp object];
		if([obj isKindOfClass:[NSString class]]){
			NSString *xml = (NSString *)obj;
			// TODO 解析
			NSLog(xml);
		}
	}else{
		// TODO 请求错误
	}
	
	return ret;
}

/**
 * 获取指定数量的Tag
 * 对于获取 Tag 而言，一般不需要认证
 */
-(NSArray *) getHotTag:(NSInteger)num{
	NSMutableArray *ret = nil;
	
	NSMutableDictionary *params = [self initParams];
	
	if(num > 0){
		[params setObject:[NSString stringWithFormat:@"%d",num] forKey:@"count"];
	}
	NSString *sig = [self genApiSign:@"flickr.tags.getHotList" params:params];
	[params setObject:sig forKey:@"api_sig"];
	
	id obj = [self invokeRemoteMethod:FLICKR_XMLRPC withMethod:@"flickr.tags.getHotList" params:params];
	
	if([obj isKindOfClass:[XMLRPCResponse class]]){
		ret = [NSMutableArray array];     // 此处使用快捷方式，不需要释放
		XMLRPCResponse *resp = (XMLRPCResponse *)obj;
		obj = [resp object];
		if([obj isKindOfClass:[NSString class]]){
			NSString *xml = (NSString *)obj;
			// TODO 解析
			NSLog(xml);
			DocumentBuilder *builder = [[DocumentBuilder alloc] init];
			Document *dom = [builder parseWithString:xml];
			[builder release];
			
			int stat = [self isRspFail:dom];
			if(stat != PARSE_RSP_FAILD){
				Element *root = [dom rootNode];
				NSString *cn = [root getAttribute:@"count"];
				if(cn){
					int len = [cn intValue];
					TextNode *tagname;
					for (int i = 0; i < len; i++) {
						tagname = (TextNode *)[dom query:[NSString stringWithFormat:@"hottags/tag[%d]/#TEXT", i]];
						if(tagname){
							[ret addObject:tagname.text];
						}
					}
				}
			}			
		}
	}else{
		// TODO 请求错误
	}
	
	return ret;
}


#pragma mark -
#pragma mark Photo Search

/**
 * 搜索图片
 * 根据 params 的不同参数，进行相应功能的搜寻
 */
-(id)searchPhoto:(NSMutableDictionary *)params{
	// 对于 params 而言，外部只需要设置好相应的查询数据，其余的内容由本方法设置即可。
	NSMutableArray *ret = nil;
	
	NSString *method = @"flickr.photos.search";
	NSString *sig = [self genApiSign:method params:params];
	[params setObject:sig forKey:@"api_sig"];
	
	id obj = [self invokeRemoteMethod:FLICKR_XMLRPC withMethod:method params:params];
	
	NSError *err = nil;
	if([obj isKindOfClass:[XMLRPCResponse class]]){
		XMLRPCResponse *resp = (XMLRPCResponse *)obj;
		obj = [resp object];
		if([obj isKindOfClass:[NSString class]]){
			NSString *xml = (NSString *)obj;
			// TODO 解析
#ifdef debug
			NSLog(xml);
#endif
			
			DocumentBuilder *builder = [[DocumentBuilder alloc] init];
			Document *dom = [builder parseWithString:xml];
			[builder release];
			
			int stat = [self isRspFail:dom];
			
			if(stat != PARSE_RSP_FAILD){
				// TODO 解析图像
				ret = [NSMutableArray array];
				Element *photo = [dom query:@"photos/photo"];
				PhotoInfo *pi;
				// 循环遍历所有的标记
				Node *pe1 = photo;
				while(pe1 != nil){
					if([pe1 isKindOfClass:[Element class]]){
						photo = (Element *)pe1;
						pi = [[[PhotoInfo alloc] init] autorelease];
						[pi setProperties:[photo getAttributes]];
						[ret addObject:pi];
					}
					pe1 = [pe1 getNextSibling];
				}
			}else{
				// TODO 解析错误
				Element *ee = [dom query:@"rsp/err"];
				if(ee){
					NSString *ecode = [ee getAttribute:@"code"];
					NSString *emsg = [ee getAttribute:@"msg"];
					err = [self makeError:[ecode intValue] withMessage:emsg];					
				}
			}
		}else{
			// TODO 请求 XML-RPC 出错
			
		}
	}else{
		err = (NSError *)obj;
	}	
	if(err){
		return err;
	}
	return ret;
}

-(NSError *)makeError:(NSInteger)code withMessage:(NSString *)msg{
	NSError *ret = nil;
	NSDictionary *dict = nil;
	if(msg){
		dict = [NSDictionary dictionaryWithObjectsAndKeys:msg,NSLocalizedDescriptionKey,nil];
	}
	ret = [NSError errorWithDomain:@"DataManager" code:code userInfo:dict];
	return ret;
}


-(void)dealloc{
	if(apiKey != nil){
		[apiKey release];
	}
	if(secretKey != nil){
		[secretKey release];
	}
	if(frob != nil){
		[frob release];
	}
	if(desc != nil){
		[desc release];
	}
	if(userInfo != nil){
		[userInfo release];
	}
	if(uploadItems != nil){
		[uploadItems release];
	}
	[super dealloc];
}

@end
